﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Globalization;

namespace SwirlTree
{

    public partial class Form1 : Form
    {
        private Bitmap b = new Bitmap(2048, 2048);
        private SwirlParametersBase m_tree;
        private string saveFileName = null;

        private static CultureInfo cultureInfo = CultureInfo.GetCultureInfo("en-US");

        public Form1()
        {
            InitializeComponent();

            m_tree = setup();
            treeNodes.Nodes.Add(m_tree);
            treeNodes.ExpandAll();
        }

        SwirlParametersBase setup()
        {
            SwirlParametersBase r = new SwirlParametersBase("root");
            r.curX = 1024;
            r.curY = 2048;
            r.radius = -4000.0;
            r.targetRadius = -3980.0;
            r.width = 20.0;
            r.targetWidth = 1.0;
            r.angle = 0.5;

            SwirlParameterChild ppp = new SwirlParameterChild("lev 3");
            ppp.radius = 50;
            ppp.targetRadius = 20;
            ppp.angle = -10;
            ppp.targetWidth = 1.0;

            ppp.numSwirls = 10;
            ppp.startPercentage = 0.10;
            ppp.endPercentage = 0.90;

            SwirlParameterChild pp = new SwirlParameterChild("lev 2");
            pp.radius = 100;
            pp.targetRadius = 80;
            pp.angle = -6;
            pp.targetWidth = 1.0;

            pp.numSwirls = 20;
            pp.startPercentage = 0.10;
            pp.endPercentage = 0.90;
            pp.Add(ppp);

            SwirlParameterChild p = new SwirlParameterChild("lev 1");
            p.radius = 500;
            p.targetRadius = 20;
            p.targetWidth = 5.0;
            p.angle = -2;
            p.numSwirls = 5;
            p.startPercentage = 0.20;
            p.endPercentage = 0.80;
            p.Add(pp);

            r.Add(p);

            return r;
        }


        private void DrawSwirl(Graphics g, double dangle, SwirlParametersBase r, CMYK inheritColor, int limitSteps)
        {
            Point[] p = new Point[4];

            CMYK startColor = r.startColor;
            if (r.inheritColor) startColor = inheritColor;
            CMYK endColor = r.endColor;

            Vector2D po = new Vector2D((int)r.curX, (int)r.curY);

            Vector2D dbase = new Vector2D(r.radius, 0);
            dbase = dbase.rotate(dangle);

            Vector2D v1 = new Vector2D(-r.width + r.radius, 0);
            Vector2D v2 = new Vector2D(r.width + r.radius, 0);
            v1 = v1.rotate(dangle);
            v2 = v2.rotate(dangle);
            v1 = v1 - dbase;
            v2 = v2 - dbase;
            p[0] = (v1 + po).getPoint();
            p[1] = (v2 + po).getPoint();

            int steps = r.steps;
            if (limitSteps > 0)
                steps = limitSteps;

            for (int i = 0; i < steps; i++)
            {
                double alpha = ((double)i) / (double)(steps -1);
                double curRadius = r.radius + (r.targetRadius - r.radius) * alpha;
                double curAngle = r.angle * alpha;
                double curWidth = r.width + (r.targetWidth - r.width) * alpha;

                v1 = new Vector2D(-curWidth + curRadius, 0);
                v2 = new Vector2D(curWidth + curRadius, 0);
                v1 = v1.rotate(dangle + curAngle) - dbase;
                v2 = v2.rotate(dangle + curAngle) - dbase;

                p[2] = (v2 + po).getPoint();
                p[3] = (v1 + po).getPoint();

                CMYK curColor = CMYK.alpha(startColor, endColor, alpha);

                SolidBrush b = new SolidBrush(ColorStuff.CMYKtoRGB(curColor));
                g.FillPolygon(b, p);


                p[0] = p[3];
                p[1] = p[2];

            }

            for (int i = 0; i < r.Nodes.Count; i++)
            {
                SwirlParameterChild c = (SwirlParameterChild)r.Nodes[i];
                double start = c.startPercentage;
                double remaining = c.endPercentage - start;

                double storeAngle = c.angle;
                double storeRadius = c.radius;
                double storeTargetRadius = c.targetRadius;

                for (int j = 0; j < c.numSwirls; j++)
                {
                    double cur;
                    if (c.numSwirls != 1)
                    {
                        cur = start + (remaining * ((double)j / (double)(c.numSwirls - 1)));
                    }
                    else
                    {
                        cur = start;
                    }
                    double curRadius = r.radius + (r.targetRadius - r.radius) * cur;
                    double curAngle = r.angle * cur;
                    double curWidth = r.width + (r.targetWidth - r.width) * cur;

                    v1 = new Vector2D(curRadius, 0);
                    v1 = (v1.rotate(dangle + curAngle) - dbase) + po;

                    c.curX = v1._x;
                    c.curY = v1._y;
                    c.width = curWidth;

                    c.angle = -c.angle;
                    c.radius = -c.radius;
                    c.targetRadius = -c.targetRadius;

                    CMYK curColor = CMYK.alpha(startColor, endColor, cur);

                    DrawSwirl(g, curAngle, c, curColor, limitSteps);
                }
                c.angle = storeAngle;
                c.radius = storeRadius;
                c.targetRadius = storeTargetRadius;
            }
        }

        private void RenderTree(int limitSteps)
        {
            Cursor.Current = Cursors.WaitCursor;

            Graphics g = Graphics.FromImage(b);
            g.Clear(Color.Transparent);
//            g.FillRectangle(Brushes.White, 0, 0, 2048, 2048);

            if (treeNodes.Nodes.Count > 0)
            {
                SwirlParametersBase treeBase = (SwirlParametersBase)treeNodes.Nodes[0];

                DrawSwirl(g, 0, m_tree, m_tree.startColor, limitSteps);
            }
            g.Dispose();
            pictureBox1.Image = b;

            Cursor.Current = Cursors.Default;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            RenderTree(-1);
        }

        private void saveButton_Click(object sender, EventArgs e)
        {
            b.Save("swirl.png");
        }

        private void treeNodes_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {

                // Point where the mouse is clicked.
                Point p = new Point(e.X, e.Y);

                // Get the node that the user has clicked.
                TreeNode node = treeNodes.GetNodeAt(p);
                if (node != null)
                {

                    // Select the node the user has clicked.
                    // The node appears selected until the menu is displayed on the screen.
                    treeNodes.SelectedNode = node;

                    SwirlParametersBase swirl = (SwirlParametersBase)node;
                    if (swirl.isRoot)
                        MnuRootTreeNode.Show(treeNodes, p);
                    else
                        MnuTreeNode.Show(treeNodes, p);
                    /*
                    // Find the appropriate ContextMenu depending on the selected node.
                    switch (Convert.ToString(node.Tag))
                    {
                        case "TextFile":
                            mnuTextFile.Show(treeView1, p);
                            break;
                        case "File":
                            mnuFile.Show(treeView1, p);
                            break;
                    }
                     */
                }
            }

        }

        private void removeChild(object sender, EventArgs e)
        {
            TreeNode curNode = treeNodes.SelectedNode;
            curNode.Remove();
        }

        private void addChild(object sender, EventArgs e)
        {
            TreeNode curNode = treeNodes.SelectedNode;
            int curNumberNodes = curNode.Nodes.Count;
            string nodeName = "node Lev:" + curNode.Level + " " + (curNumberNodes + 1);
            curNode.Nodes.Add(new SwirlParameterChild(nodeName));
        }

        private void treeNodes_AfterSelect(object sender, TreeViewEventArgs e)
        {
            TreeNode curNode = treeNodes.SelectedNode;

            SwirlParametersBase swirl = (SwirlParametersBase)curNode;

            radiusBox.Text = Convert.ToString(swirl.radius, cultureInfo);
            targetRadiusBox.Text = Convert.ToString(swirl.targetRadius, cultureInfo);
            targetWidthBox.Text = Convert.ToString(swirl.targetWidth, cultureInfo);
            angleBox.Text = Convert.ToString(swirl.angle, cultureInfo);
            iterationsBox.Text = Convert.ToString(swirl.steps, cultureInfo);

            inheritColorCheckBox.Checked = swirl.inheritColor;
            if (inheritColorCheckBox.Checked)
                startColorButton.BackColor = Button.DefaultBackColor;
            else
                startColorButton.BackColor = ColorStuff.CMYKtoRGB(swirl.startColor);
            endColorButton.BackColor = ColorStuff.CMYKtoRGB(swirl.endColor);

            if (swirl.isRoot)
            {
                startPercentageBox.Enabled = false;
                endPercentageBox.Enabled = false;
                numberSwirlsBox.Enabled = false;
                startXBox.Enabled = true;
                startYBox.Enabled = true;
                startWidthBox.Enabled = true;
                startXBox.Text = Convert.ToString(swirl.curX, cultureInfo);
                startYBox.Text = Convert.ToString(swirl.curY, cultureInfo);
                startWidthBox.Text = Convert.ToString(swirl.width, cultureInfo);
                inheritColorCheckBox.Enabled = false;
            }
            else
            {
                SwirlParameterChild child = (SwirlParameterChild)swirl;
                startPercentageBox.Text = Convert.ToString(child.startPercentage, cultureInfo);
                endPercentageBox.Text = Convert.ToString(child.endPercentage, cultureInfo);
                numberSwirlsBox.Text = Convert.ToString(child.numSwirls, cultureInfo);
                startPercentageBox.Enabled = true;
                endPercentageBox.Enabled = true;
                numberSwirlsBox.Enabled = true;
                startXBox.Enabled = false;
                startYBox.Enabled = false;
                inheritColorCheckBox.Enabled = true;
            }

        }

        private void radiusBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                double isNumber = 0;
                if (double.TryParse(radiusBox.Text, NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out isNumber))
                {
                    ((SwirlParametersBase)treeNodes.SelectedNode).radius = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void targetRadiusBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                double isNumber = 0;
                if (double.TryParse(targetRadiusBox.Text, NumberStyles.Any, cultureInfo, out isNumber))
                {
                    ((SwirlParametersBase)treeNodes.SelectedNode).targetRadius = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void targetWidthBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                double isNumber = 0;
                if (double.TryParse(targetWidthBox.Text, NumberStyles.Any, cultureInfo, out isNumber))
                {
                    ((SwirlParametersBase)treeNodes.SelectedNode).targetWidth = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void angleBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                double isNumber = 0;
                if (double.TryParse(angleBox.Text, NumberStyles.Any, cultureInfo, out isNumber))
                {
                    ((SwirlParametersBase)treeNodes.SelectedNode).angle = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void iterationsBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                int isNumber = 0;
                if (int.TryParse(iterationsBox.Text, NumberStyles.Any, cultureInfo, out isNumber))
                {
                    ((SwirlParametersBase)treeNodes.SelectedNode).steps = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void startPercentageBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                double isNumber = 0;
                if (double.TryParse(startPercentageBox.Text, NumberStyles.Any, cultureInfo, out isNumber))
                {
                    ((SwirlParameterChild)treeNodes.SelectedNode).startPercentage = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void endPercentageBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                double isNumber = 0;
                if (double.TryParse(endPercentageBox.Text, NumberStyles.Any, cultureInfo, out isNumber))
                {
                    ((SwirlParameterChild)treeNodes.SelectedNode).endPercentage = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void numberSwirlsBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                int isNumber = 0;
                if (int.TryParse(numberSwirlsBox.Text, out isNumber))
                {
                    ((SwirlParameterChild)treeNodes.SelectedNode).numSwirls = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            openFileDialog1.Filter = "swirltree (*.st)|*.st|All files (*.*)|*.*";
            openFileDialog1.FilterIndex = 1;
            openFileDialog1.RestoreDirectory = true;

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                string filename = openFileDialog1.FileName;
                m_tree = Serializer.DeSerializeObject(filename);
                treeNodes.Nodes.Clear();
                treeNodes.Nodes.Add(m_tree);
            }
        }

        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "swirltree (*.st)|*.st|All files (*.*)|*.*";
            saveFileDialog.FilterIndex = 1;
            saveFileDialog.RestoreDirectory = true;

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                string filename = saveFileDialog.FileName;
                saveFileName = filename;
                Serializer.SerializeObject(filename, m_tree);
            }
        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {

        }

        private void startXBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                double isNumber = 0;
                if (double.TryParse(startXBox.Text, NumberStyles.Any, cultureInfo, out isNumber))
                {
                    ((SwirlParametersBase)treeNodes.SelectedNode).curX = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void startYBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                double isNumber = 0;
                if (double.TryParse(startYBox.Text, NumberStyles.Any, cultureInfo, out isNumber))
                {
                    ((SwirlParametersBase)treeNodes.SelectedNode).curY = isNumber;
                    RenderTree(20);
                }
            }
        }

        private void startColorButton_Click(object sender, EventArgs e)
        {
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                startColorButton.BackColor = colorDialog1.Color;
                Color foreColor = Color.FromArgb(255, (byte)(255 - colorDialog1.Color.R), (byte)(255 - colorDialog1.Color.G), (byte)(255 - colorDialog1.Color.B));
                startColorButton.ForeColor = foreColor;
                ((SwirlParametersBase)treeNodes.SelectedNode).startColor = ColorStuff.RGBtoCMYK(colorDialog1.Color);
            }
        }

        private void endColorButton_Click(object sender, EventArgs e)
        {
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                endColorButton.BackColor = colorDialog1.Color;
                Color foreColor = Color.FromArgb(255, (byte)(255 - colorDialog1.Color.R), (byte)(255 - colorDialog1.Color.G), (byte)(255 - colorDialog1.Color.B));
                endColorButton.ForeColor = foreColor;
                ((SwirlParametersBase)treeNodes.SelectedNode).endColor = ColorStuff.RGBtoCMYK(colorDialog1.Color);
            }
        }

        private void inheritColorCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (inheritColorCheckBox.Checked)
                startColorButton.Enabled = false;
            else
                startColorButton.Enabled = true;
            ((SwirlParametersBase)treeNodes.SelectedNode).inheritColor = inheritColorCheckBox.Checked;
        }

        private void renderPreview_Click(object sender, EventArgs e)
        {
            RenderTree(20);
        }

        private void startWidthBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                double isNumber = 0;
                if (double.TryParse(startWidthBox.Text, NumberStyles.Any, cultureInfo, out isNumber))
                {
                    ((SwirlParametersBase)treeNodes.SelectedNode).width = isNumber;
                    RenderTree(20);
                }
            }
        }
    }
}
